#include <cppwinks/utility/log/Log.h>
#include <cppwinks/utility/format/Format.h>
#include <cppwinks/network/http/Http.h>
#include <cppwinks/network/tcp/TcpServer.h>
#include <util/HttpUriRegistrar.h>
#include <util/MSingletonFactory.h>
#include <service/ChatService.h>
#include <util/HttpContext.h>

using namespace std;
using namespace format;
using namespace network;
using namespace singleton;

std::unordered_map<ClientConnection *, HttpContext> http_contexts;

void dispatchHttpRequest(ClientConnection *client, shared_ptr<HttpRequest> req)
{
    string url = req->getUrl();
    cout << url << endl;
    string method = req->getMethod();
    HttpUriRegistrar::HttpHandler handler = nullptr;
    if (method == "GET")
    {
        handler = MSingletonFactory::getMFactory()->getSingleton<HttpUriRegistrar>("HttpUriRegistrar")->getHandler(url);
    }
    else if (method == "POST")
    {
        handler = MSingletonFactory::getMFactory()->getSingleton<HttpUriRegistrar>("HttpUriRegistrar")->PostHandler(url);
    }
    if (handler == nullptr)
    {
        HttpReply rep("404");
        client->send(rep.toString());
        client->disconnect();
        return;
    }
    HttpReply rep = handler(*req);
    rep.addHeader("Content-Length", to_string(rep.getBody().size()));
    client->send(rep.toString());
    client->disconnect();
}

void http_recv_cb(ClientConnection *client)
{
    if (http_contexts.count(client) == 1)
    {
        HttpContext http_context = http_contexts.at(client);
        if (http_context.getStatus() == "body-not-finished")
        {
            shared_ptr<HttpRequest> req = http_context.getRequest();
            int length = atoi(req->getHeader("Content-Length").c_str());
            string data = req->getBody();
            data.append(client->read());
            req->setBody(data);
            if (length > (data.length() + 1))
            {
                return;
            }
            else
            {
                dispatchHttpRequest(client, req);
                http_contexts.erase(client);
            }
        }
    }
    else
    {
        shared_ptr<HttpRequest> req = make_shared<HttpRequest>();
        try
        {
            string requestData = client->read();
            req->parse(requestData);
        }
        catch (const std::exception &e)
        {
            cout << e.what() << endl;
            client->disconnect();
            return;
        }
        if (req->hasHeader("Content-Length"))
        {
            string context_length = req->getHeader("Content-Length");
            int length = atoi(context_length.c_str());
            if (length > (req->getBody().length() + 1))
            {
                http_contexts.emplace(client, HttpContext(req, "body-not-finished"));
                return;
            }
        }
        dispatchHttpRequest(client, req);
    }
}

void tcp_accept_cb(ClientConnection *client)
{
    chat_service->set(client);
}

void tcp_recv_cb(ClientConnection *client)
{
    chat_service->send(client, client->read());
}

void tcp_close_cb(ClientConnection *client)
{
    chat_service->remove(client);
}

int main()
{
    // 创建Reactor模型
    Reactor reactor;
    // 设置Reactor模型线程数量
    reactor.addThread(1);
    // 创建Tcp服务器，设置有数据时的回调函数、监听端口和Reactor模型实例
    TcpServer http_server(http_recv_cb, 9000, &reactor);
    // 初始化服务端
    http_server.init();
    cout << Format("http server start on {0}", 9000) << endl;
    // 创建Tcp服务器，设置有数据时的回调函数、监听端口和Reactor模型实例
    TcpServer tcp_server(tcp_recv_cb, 9001, &reactor);
    // 设置客户端断开连接时的回调函数
    tcp_server.setCloseCallBack(tcp_close_cb);
    // 设置客户端建立连接时的回调函数
    tcp_server.setAcceptCallBack(tcp_accept_cb);
    // 初始化服务端
    tcp_server.init();
    cout << Format("tcp server start on {0}", 9001) << endl;
    reactor.loop();
    return 0;
}